var dui = (function (doc) {
	function $(selector, parent) {
		var type = '';
		var p = parent ? parent : document;
    var obj = null;
		var eq = 0;
		var sel = selector;
		
		switch (sel.charAt(0)) {
			case '.': type = 'class'; break;
			case '#': type = 'id'; break;
			 default: type = 'tag'; break;
		}
		
		if (/:eq/.test(selector)) {
			eq = sel.match(/:eq(\((\d+)\))/)[2];
			sel = sel.replace(/:eq.*/, '');
		}
		
		if (/^[.#]/.test(selector)) {
			sel = sel.substr(1);
		}

		if (type == 'class') {
			obj = getByClass(p, sel);

			if (obj) {
				if (eq) {
					return obj[eq];
				} else {
				  return obj;
				}
			} else return null;
		} else if (type == 'id') {
			obj = p.getElementById(sel);
			if (obj) return obj;
			else return null;
		} else {
			obj = p.getElementsByTagName(sel);

			if (obj) {
				if (eq) {
					return obj[eq];
				} else {
				  return obj;
				}
			} else return null;
		}
	}
	
	function show(obj) {
		obj.style.display = 'block';
	}
	
	function hide(obj) {
		obj.style.display = 'none';
	}
	
	function delClass(obj, klass) {
		if (!klass) return;
		obj.className = trim(obj.className.replace(new RegExp('\\b' + klass + '\\b', 'ig'), ''));
		if (!obj.className) obj.removeAttribute('class');
	}
	
	function addClass(obj, klass) {
		if (!klass) return;
		if (!new RegExp('\\b' + klass + '\\b', 'ig').test(obj.className)) obj.className = trim(obj.className) + ' ' + klass;
	}
	
	function hasClass(obj, klass) {
		if (!klass) return;
		if (new RegExp('\\b' + klass + '\\b', 'ig').test(obj.className)) return true;
		else return false;
	}
	
	function trim(str) {
		return str.replace(/((\s)+)/ig, '$2').replace(/^[\s\b]|[\s\b]$/ig, '');
	}
	
	function objType(obj) {
		return Object.prototype.toString.call(obj);
	}
	
	function getByClass(obj, klass, index) {
		var re = new RegExp('\\b' + klass + '\\b', 'ig');
		var aElm = obj.getElementsByTagName('*');
		var aResult = [];

		for (var i = 0, len = aElm.length; i < len; i++) {
			if (re.test(aElm[i].className)) aResult.push(aElm[i]);
		}

		if (index) {
			if (aResult[index]) return aResult[index];
			else return null;
		}
		
		return aResult;
	}
	
	function parents(obj, selector) {
		var type  = selector.charAt(0);
    
		while (obj) {
			obj = obj.parentNode;
			
			if (type == '.') {
				if (obj && new RegExp('\\b' + selector.substr(1) + '\\b').test(obj.className)) return obj;
			} else if (type == '#') {
				if (obj && selector.substr(1) == obj.id) return obj;
			} else {
				if (obj && new RegExp('\\b' + selector.toUpperCase() + '\\b').test((obj.tagName + '').toUpperCase())) return obj;
			}
		}
		
		return null;
	}
	
	function bind(obj, events, fn) {
		if (obj.addEventListener) {
			obj.addEventListener(events, fn, false);	
		} else {
			obj.attachEvent('on'+events, function () {
				fn.call(obj);
			});
		}
		
		return obj;
	}
	
	function each(data, fn) {
		if (objType(data) == '[object Array]') {
			for (var i = 0, len = data.length; i < len; i++) fn.call(data[i], data[i], i);
		} else if (objType(data) == '[object HTMLCollection]') {
			var arr = [];
			for (var i = 0, len = data.length; i < len; i++) arr.push(data[i]);
			for (var i = 0, len = arr.length; i < len; i++) fn.call(arr[i], arr[i], i);
		} else if (objType(data) == '[object Object]') {
			for (var i in data) fn.call(data[i], data[i], i);
		}
	}
	
	function first(obj) {
    return obj.firstElementChild || obj.firstChild;
  }

  function last(obj) {
    return obj.lastElementChild || obj.lastChild;
  }

  function next(obj) {
    return obj.nextElementSibling || obj.nextSibling;
  }

  function prev(obj) {
    return obj.previousElementSibling || obj.previousSibling;
  }
	
	function siblings(obj) {
		var parent = obj.parentNode;
		var aChild = parent.children;
		var aResult = [];
		
		for (var i = 0, len = aChild.length; i < len; i++) if (aChild[i] != obj) aResult.push(aChild[i]);

		return aResult;
	}
	
	function child(obj, num) {
		return obj.children[num];
	}
	
	function animate(obj, json, fn, times) {
    clearInterval(obj.timer);
		
		var time = 30;
		if (times) time = Math.round(times / 13);
		
    obj.timer = setInterval(function () {
      var bFlag = true;
        
      for (var attr in json) {
        var iCur = 0;
            
        if (attr == 'opacity') {
          iCur = Math.round(parseFloat(css(obj, attr)) * 100);    
        } else if (attr == 'scroll') {
          iCur = scrollTop();    
        } else {
          iCur = parseInt(css(obj, attr));
        }

        var iSpeed = (json[attr] - iCur) / 8;
        iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);
            
        if (attr == 'opacity') {
          obj.style.filter = 'alpha(opacity=' + (iSpeed + iCur) + ')';
          obj.style.opacity = (iSpeed + iCur) / 100;    
        } else if (attr == 'scroll') {
          scrollTop(iSpeed + iCur);    
        } else {
          obj.style[attr] = (iSpeed + iCur) + 'px';    
        }
            
        if (json[attr] != iCur) {
          bFlag = false;    
        }
      }
        
      if (bFlag) {
        clearInterval(obj.timer);
        if (fn) {
          fn.call(obj);    
        }
      }
    }, time);    
  }

  function css(obj, attr, value) {
		if (objType(attr) == '[object Object]') {
			for (var i in attr) {
				setStyle(obj, i, attr[i]);
			}
		} else if (objType(attr) == '[object Array]') {
			var result = [];
			
			each(attr, function (elm, index) {
			  result.push(setStyle(obj, attr[index]));
			});
			
			return result;
		} else if (objType(attr) == '[object String]') {
		  return setStyle(obj, attr, value);
		}
  }
	
	function setStyle(obj, attr, value) {
		if (value) return obj.style[attr] = value;

		var attribute = attr.replace(/-(\w)/ig, function ($1, $2) {
			return ($2 + '').toUpperCase();
		});

    if (obj.currentStyle) {
      return obj.currentStyle[attribute];    
    } else {
      return getComputedStyle(obj, false)[attribute];    
    }
	}
	
	function scrollTop(value) {
		value && (doc.documentElement.scrollTop = doc.body.scrollTop = value);
		return doc.documentElement.scrollTop || doc.body.scrollTop;
	}
	
	function scrollLeft(value) {
		value && (doc.documentElement.scrollLeft = doc.body.scrollLeft = value);
		return doc.documentElement.scrollLeft || doc.body.scrollLeft;
	}
	
	function viewHeight() {
		return doc.documentElement.clientHeight;
	}
	
	function viewWidth() {
		return doc.documentElement.clientWidth;
	}
	
	function documentHeight() {
		return Math.max(doc.body.offsetHeight, doc.documentElement.clientHeight);
	}
	
	function maxZ(obj) {
		var elms = (obj || doc).getElementsByTagName('*'), z = 0, arr = [];
		
		for (var i = 0, len = elms.length; i < len; i++) {
			var z = parseInt(setStyle(elms[i], 'z-index'));
			arr.push(isNaN(z) ? 0 : z);
		}
		
		return Math.max.apply(null, arr);
	}
	
	function insertAfter(parent, before, after) {
		parent.insertBefore(after, before);
	  parent.insertBefore(before, after);
	}
	
	function append(parent, child) {
		(parent || doc).appendChild(child);
	}
	
	function klass(obj, value) {
		if (value) obj.className = value;
		else return obj.className;
	}
	
	function outerWidth(obj) {
		var tmp = obj.cloneNode(true);
		var w = 0;
		
		obj.parentNode.appendChild(tmp);
		
		tmp.style.display = 'block';
		
		w = parseInt(css(tmp, 'padding-left')) + parseInt(css(tmp, 'padding-right')) + parseInt(css(tmp, 'margin-left')) + parseInt(css(tmp, 'margin-right')) + parseInt(css(tmp, 'border-left-width')) + parseInt(css(tmp, 'border-right-width')) + parseInt(css(tmp, 'width'));
		
		obj.parentNode.removeChild(tmp);

		return w;
	}
	
	function outerHeight(obj) {
		var tmp = obj.cloneNode(true);
		var h = 0;
		
		obj.parentNode.appendChild(tmp);
		
		tmp.style.display = 'block';
		
		h = parseInt(css(tmp, 'padding-top')) + parseInt(css(tmp, 'padding-bottom')) + parseInt(css(tmp, 'margin-top')) + parseInt(css(tmp, 'margin-bottom')) + parseInt(css(tmp, 'border-top-width')) + parseInt(css(tmp, 'border-bottom-width')) + parseInt(css(tmp, 'height'));
		
		obj.parentNode.removeChild(tmp);

		return h;
	}
	
	function html(obj, value) {
		if (value) obj.innerHTML = value;
		else return obj.innerHTML;
	}
	
	return {
		$: $,
		css: css,
		bind: bind,
		each: each,
		parents: parents,
		animate: animate,
		scrollTop: scrollTop,
		scrollLeft: scrollLeft,
		getByClass: getByClass,
		addClass: addClass,
		delClass: delClass,
		hasClass: hasClass,
		siblings: siblings,
		first: first,
		last: last,
		prev: prev,
		next: next,
		trim: trim,
		hide: hide,
		show: show,
		scrollTop: scrollTop,
		scrollLeft: scrollTop,
		viewHeight: viewHeight,
		viewWidth: viewWidth,
		documentHeight: documentHeight,
		maxZ: maxZ,
		insertAfter: insertAfter,
		append: append,
		klass: klass,
		outerWidth: outerWidth,
		outerHeight: outerHeight,
		html: html
	};
})(document);